package com.woniuxy.core.listener;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import com.woniuxy.core.service.ArticleLikeService;
import com.woniuxy.core.service.UserStatsService;
import com.woniuxy.entity.AllArticle;
import com.woniuxy.entity.ArticleLike;
import com.woniuxy.enums.article.ArticleLikeStatus;
import com.woniuxy.enums.article.ArticleLikeType;
import com.woniuxy.enums.redis.user.LikeRedisKeyEnum;
import com.woniuxy.feign.ContentFeignClient;
import com.woniuxy.mq.message.LikeMessage;
import com.woniuxy.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.client.ResourceAccessException;

import java.io.IOException;
import java.util.Date;
import java.util.Objects;

/**
 * @author 饶志
 * @version 1.0
 * @since 2025-07-15  11:05
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class LikeMessageListener {

    private final ArticleLikeService articleLikeService;

    private final UserStatsService userStatsService;

    private final ContentFeignClient contentFeignClient;

    private final LoadBalancerClient loadBalancerClient;

    private final RedisUtil redisUtil;

    // 监听点赞队列
    @RabbitListener(queues = "like_queue")
    @Transactional
    public void handleLikeMessage(LikeMessage message, Channel channel,
                                  @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                                  @Header(AmqpHeaders.MESSAGE_ID) String messageId) {
        log.debug("==========handleLikeMessage--start-->>");
        log.debug("message:{}", message);
        log.debug("messageId:{}", messageId);
        try {
            // 消息幂等性校验
            String processedKey = LikeRedisKeyEnum.LIKE_QUEUE_PROCESSED_MSG_ID.format(messageId);
            if (redisUtil.hasKey(processedKey)) {
                log.debug("消息已处理，跳过重复消费，messageId:{}", messageId);
                channel.basicAck(deliveryTag, false); // 直接确认
                return;
            }

            // 查询是否存在历史记录
            ArticleLike likeRecord = articleLikeService.getOne(
                    new QueryWrapper<ArticleLike>()
                            .eq("user_id", message.getUserId())
                            .eq("target_id", message.getTargetId())
                            .eq("target_type", message.getTargetType())
            );

            if (Objects.equals(message.getStatus(), ArticleLikeStatus.LIKE.getStatus())) { // 点赞
                if (likeRecord == null) {
                    // 新增记录
                    likeRecord = new ArticleLike();
                    likeRecord.setUserId(message.getUserId());
                    likeRecord.setTargetId(message.getTargetId());
                    likeRecord.setTargetType(message.getTargetType());
                    likeRecord.setStatus(ArticleLikeStatus.LIKE.getStatus());
                    likeRecord.setCreateTime(new Date());
                    articleLikeService.save(likeRecord);
                } else {
                    // 更新状态为已点赞
                    likeRecord.setStatus(ArticleLikeStatus.LIKE.getStatus());
                    likeRecord.setUpdateTime(new Date());
                    articleLikeService.updateById(likeRecord);
                }
            } else { // 取消点赞
                if (likeRecord != null) {
                    likeRecord.setStatus(ArticleLikeStatus.DISLIKE.getStatus());
                    likeRecord.setUpdateTime(new Date());
                    articleLikeService.updateById(likeRecord);
                }
            }

            if (Objects.equals(message.getTargetType(), ArticleLikeType.POST.getTargetType())) {

                // 解析服务实例信息
//                ServiceInstance instance = loadBalancerClient.choose("campus-content"); // 替换为你的服务名
//                if (instance != null) {
//                    log.debug("Feign调用的服务实例IP: {}:{}", instance.getHost(), instance.getPort());
//                }

                // 计算openfeign调用耗时
//                long startTime = System.currentTimeMillis();
                // 获取被点赞帖子信息
                Long authorId = contentFeignClient.getAuthorIdByArticleId(message.getTargetId());
//                log.debug("openfeign调用content服务获取帖子信息耗时:{}ms", System.currentTimeMillis() - startTime);

                if (authorId != null) {
                    // 计算点赞数变化量: 点赞+1，取消点赞-1
                    int delta = Objects.equals(message.getStatus(), ArticleLikeStatus.LIKE.getStatus()) ? 1 : -1;
                    log.debug("authorId:{},delta:{}", authorId, delta);

                    // 更新帖子发布者的统计信息的获赞数数据库行锁保证原子性）
                    userStatsService.update()
                            .setSql("like_count = like_count + " + delta)
                            .eq("user_id", authorId)
                            .update();
                }
            }

            log.debug("==========handleLikeMessage-->>end----\n");
            // 记录消息为已处理
            redisUtil.set(processedKey, "1", 60 * 60 * 6);

            // 业务逻辑成功，事务提交后回调，手动确认消息
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    try {
                        channel.basicAck(deliveryTag, false);
                    } catch (IOException e) {
                        log.error("消息确认失败: {}", e.getMessage());
                    }
                }
            });
        } catch (Exception e) {
            boolean requeue = false;
            try {
                // 判断是否为可重试异常（数据库连接异常、Feign调用超时等）
                if (e instanceof IOException || e instanceof ResourceAccessException) {
                    requeue = true; // 可重试异常，允许重新入队
                }

                // 业务异常，拒绝消息（requeue=true 表示重新入队，可根据需求调整）
                channel.basicNack(deliveryTag, false, requeue);
            } catch (IOException ex) {
                log.error("消息拒绝失败: {}", ex.getMessage());
            }
            log.error("处理点赞消息失败: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

}
